package ch01.shiro.authenticator.strategy;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.pam.AbstractAuthenticationStrategy;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.util.CollectionUtils;

import java.util.Collection;
import java.util.Collections;

/**
 * Created by zc on 2016/11/2.
 */
public class AtLeastTwoAuthenticatorStrategy extends AbstractAuthenticationStrategy {
    private static Logger logger = LogManager.getLogger(AtLeastTwoAuthenticatorStrategy.class);

    @Override
    public AuthenticationInfo beforeAllAttempts(Collection<? extends Realm> realms, AuthenticationToken token) throws AuthenticationException {
        logger.info("beforeAllAttempts");
        return new SimpleAuthenticationInfo();
    }

    @Override
    public AuthenticationInfo beforeAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
        logger.info("beforeAttempt");
        return aggregate;
    }

    @Override
    public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
        logger.info("afterAttempt");
        AuthenticationInfo info;
        if(singleRealmInfo == null){
            info = aggregateInfo;
        } else {
            if(aggregateInfo == null){
                info = singleRealmInfo;
            } else {
                info = merge(singleRealmInfo,aggregateInfo);
            }
        }
        return info;
    }

    @Override
    public AuthenticationInfo afterAllAttempts(AuthenticationToken token, AuthenticationInfo aggregate) throws AuthenticationException {
        logger.info("afterAllAttempts");
        if(aggregate == null
                || CollectionUtils.isEmpty(aggregate.getPrincipals())
                || aggregate.getPrincipals().getRealmNames().size() < 2){
            throw new AuthenticationException("Authentication token of type [" + token.getClass() + "] " +
                    "could not be authenticated by any configured realms.  Please ensure that at least two realm can " +
                    "authenticate these tokens.");
        }
        return aggregate;
    }
}
